# Created by 黄景涛
# DATE 2024/5/21
import uuid
import copy

from faker import Faker
from requests import Session
from datetime import datetime
import random
import jsonpath库
from utils.yaml_util import read_yaml
from acmdb import cmdb_obj_attrs as attrs
from acmdb.asst_tree import TreeNode, AsstTree

cfg_info = read_yaml()
fk = Faker(locale='zh_CN')


class HJTModelGroup:
    """
    模型分组
    """
    create_url: str = cfg_info.get('cmdb_base_url') + cfg_info.get('cmdb').get('objectclassification')
    search_url: str = cfg_info.get('cmdb_base_url') + cfg_info.get('cmdb').get('classificationobject')
    group_prefix_name: str = "HJT分组_"
    group_prefix_id: str = "hjtgroup"
    hjt_groups: list = []

    def __init__(self, session: Session, headers):
        self.session = session
        self.headers = headers
        self.search_hjt_groups()
        random_msg = str(datetime.now().strftime('%m%d')) + '__' + ''.join(random.choices('0123456789', k=4))
        bk_classification_name = self.group_prefix_name + random_msg
        bk_classification_id = self.group_prefix_id + random_msg
        self.data = {}
        self.data.update(bk_classification_id=bk_classification_id)
        self.data.update(bk_classification_name=bk_classification_name)
        self.data.update(bk_supplier_account=0)

    def search_hjt_groups(self):
        resp = self.session.post(self.search_url, headers=self.headers)
        hjt_groups = jsonpath库.jsonpath(resp.json(), '$..bk_classification_id')
        for group in hjt_groups:
            if group.startswith(self.group_prefix_id):
                HJTModelGroup.hjt_groups.append(group)

    def create(self):
        try:
            resp = self.session.post(self.create_url, json=self.data, headers=self.headers)
            bk_classification_id = resp.json().get('data').get('bk_classification_id')
            HJTModelGroup.hjt_groups.append(bk_classification_id)
            print(f'分组创建成功！')
        except:
            raise


class HJTModel:
    """
    模型
    """
    create_url: str = cfg_info.get('cmdb_base_url') + cfg_info.get('cmdb').get('object')
    create_inst_url: str = cfg_info.get('base_url') + cfg_info.get('acmdb').get('create_inst')
    create_asst_url: str = cfg_info.get('base_url') + cfg_info.get('acmdb').get('add_asst')
    bk_object_prefix_name: str = "auto模型_"
    bk_object_prefix_id: str = "automodule_"
    hjt_objects: list = []

    def __init__(self, bk_classification_id, session: Session, headers):
        self.session = session
        self.headers = headers

        self.data = {"bk_supplier_account": "0", "bk_obj_icon": "icon-cc-default"}
        self.data.update(bk_classification_id=bk_classification_id)
        self.data.update(userName=cfg_info.get('login').get('user'))
        # print(f'模型参数: {self.data}')

    def create(self):
        """创建模型"""
        timestamp = str(datetime.timestamp(datetime.now())).split('.')[0][-3:]
        bk_obj_name = self.bk_object_prefix_name + timestamp
        bk_obj_id = self.bk_object_prefix_id + timestamp
        self.data.update(bk_obj_name=bk_obj_name)
        self.data.update(bk_obj_id=bk_obj_id)
        try:
            resp = self.session.post(self.create_url, json=self.data, headers=self.headers)
            # print(resp.json())
            bk_object_id = resp.json().get('data').get('bk_obj_id')
            bk_obj_name = resp.json().get('data').get('bk_obj_name')
            HJTModel.hjt_objects.append([bk_object_id, bk_obj_name, False])
            print(f'模型创建成功！')
        except:
            raise

    def add_attrs(self):
        """添加属性"""
        obj_attr = ObjectAttr(self.session, self.headers)
        attr_types: list = ["SingleChar", "Int", "Float", "Date", "Time", "LongChar", "ObjUser", "TimeZone", "Bool",
                            "List", "Organization", "Enum"]
        for obj in HJTModel.hjt_objects:
            if obj[-1]:
                continue
            bk_object_id = obj[0]
            print(f'模型{bk_object_id}')
            for attr_type in attr_types:
                attr_inst = getattr(attrs, attr_type)()
                obj_attr.create_attr(attr_inst, bk_object_id)
            obj[-1] = True

    def add_asst_by_center(self):
        """添加关联类型: 第一个模型和其他所有模型之间建立关联关系"""
        obj_asst = ObjectAsst(self.session, self.headers)
        hjt_objects_copy = copy.deepcopy(HJTModel.hjt_objects)
        one_obj = hjt_objects_copy.pop(0)
        while len(hjt_objects_copy) > 0 and len(obj_asst.asst_types) > 0:
            asst_type = obj_asst.asst_types.pop()
            other_obj = hjt_objects_copy.pop()
            obj_asst.create_asst(one_obj[0], other_obj[0], asst_type)

    def add_asst_by_chain(self):
        """添加关联类型：链式添加，所有模型之间形成一条链"""
        obj_asst = ObjectAsst(self.session, self.headers)
        # hjt_objects_copy = copy.deepcopy(HJTModel.hjt_objects)
        for i in range(len(HJTModel.hjt_objects) - 1):
            obj_1 = HJTModel.hjt_objects[i]
            obj_2 = HJTModel.hjt_objects[i + 1]
            asst_type = random.choice(obj_asst.asst_types)
            obj_asst.create_asst(obj_1[0], obj_2[0], asst_type)
            bk_obj_asst_id = '_'.join([obj_1[0], asst_type, obj_2[0]])
            HJTModel.hjt_objects[i].append(bk_obj_asst_id)
            HJTModel.hjt_objects[i + 1].append(bk_obj_asst_id)
        print(f'模型信息：{HJTModel.hjt_objects}')

    def add_insts_by_tree(self, depth: int):
        """按照树结构，创建实例+添加关联"""
        ...
        tree = AsstTree()
        root = tree.create_tree(depth)
        # 深度遍历，更新每个节点中的model_info
        tree.update_node_by_dfs(root, HJTModel.hjt_objects)
        tree.print_tree(root)

        # 遍历每个节点，创建实例，并更新实例id
        tree.update_inst_by_dfs(root, self.add_insts_by_one)
        tree.print_tree(root)
        # 遍历每个节点，把当前节点与子节点，建立关联关系
        tree.update_asst_by_dfs(root, self.add_inst_asst)
        ...

    def add_insts_by_one(self, bk_inst_name, bk_obj_id):
        """创建一个实例"""
        inst_data = {"bk_inst_name": bk_inst_name, "bk_obj_id": bk_obj_id}
        try:
            resp = self.session.post(self.create_inst_url, json=inst_data, headers=self.headers)
            # print(f'实例创建结果：{resp.text}')
            print(f'\t实例【{bk_inst_name}】创建成功')
            return resp.json().get('data').get('bk_inst_id')
        except:
            raise

    def add_insts_by_simple(self, inst_count=1):
        """创建实例：单纯创建多个实例"""
        inst_data = {"bk_inst_name": None, "bk_obj_id": None}
        for model_obj in HJTModel.hjt_objects:
            bk_obj_id = model_obj[0]
            for i in range(1, inst_count + 1):
                bk_inst_name = bk_obj_id[-3:] + f'__实例{i:0>3}'
                inst_data.update(bk_obj_id=bk_obj_id, bk_inst_name=bk_inst_name)
                try:
                    resp = self.session.post(self.create_inst_url, json=inst_data, headers=self.headers)
                    # print(f'实例创建结果：{resp.text}')
                    print(f'\t实例【{bk_inst_name}】创建成功')
                except:
                    raise

    def add_inst_asst(self, bk_inst_name, bk_asst_inst_name, bk_inst_id, bk_asst_inst_id, bk_obj_asst_id, bk_obj_id):
        asst_data = {
            "bk_inst_id": bk_inst_id,
            "bk_asst_inst_id": bk_asst_inst_id,
            "bk_obj_asst_id": bk_obj_asst_id,
            "bk_obj_id": bk_obj_id,
        }
        try:
            resp = self.session.post(self.create_asst_url, json=asst_data, headers=self.headers)
            # print(f'内置的关联类型：{resp.json()}')
            asst_type = bk_obj_asst_id.split('_')[2]
            print(f'{bk_inst_name}成功【{asst_type}关联】{bk_asst_inst_name}！')
        except:
            raise


class ObjectAttr:
    """
    属性
    """
    create_url: str = cfg_info.get('cmdb_base_url') + cfg_info.get('cmdb').get('objectattr')

    # attr_types: list = ["singlechar", "int", "float", "date", "time", "longchar", "objuser", "timezone", "bool", "list","organization"]

    def __init__(self, session: Session, headers):
        self.session = session
        self.headers = headers
        self.data = {
            "bk_obj_id": "$",
            "bk_property_group": attrs.BasicAttr.attr_group,
            "bk_property_id": "$",
            "bk_property_name": "$",
            "bk_property_type": "$",
            "bk_supplier_account": "0",
            "creator": "product",
            "editable": True,
            "isrequired": False,
            "option": "",
            "placeholder": "",
            "unit": ""
        }

    def create_attr(self, attr: attrs.BasicAttr, bk_obj_id):
        cls_name = attr.__class__.__name__.lower()
        bk_property_id = cls_name + ''.join(random.choices('abcdef1234567890', k=3))
        # bk_property_id = cls_name + str(uuid.uuid4()).replace('-', '')      # 拼接uuid
        bk_property_name = attr.__class__.__doc__.strip() + '字段'
        bk_property_type = cls_name
        self.data.update(
            bk_obj_id=bk_obj_id,
            bk_property_id=bk_property_id,
            bk_property_name=bk_property_name,
            bk_property_type=bk_property_type,
            option=attr.option
        )
        try:
            resp = self.session.post(self.create_url, json=self.data, headers=self.headers)
            # print(f'属性创建结果：{resp.json()}')
            print(f'\t属性【{bk_property_name}】创建成功！')
        except:
            raise


class ObjectAsst:
    """ 模型的关联关系 """
    create_url: str = cfg_info.get('cmdb_base_url') + cfg_info.get('cmdb').get('objectassociation')
    search_url: str = cfg_info.get('cmdb_base_url') + cfg_info.get('cmdb').get('find_associationtype')
    asst_types: list = []

    def __init__(self, session: Session, headers):
        self.session = session
        self.headers = headers
        self.get_asst_types()

    def get_asst_types(self):
        """ 获取内置的关联类型 """
        try:
            resp = self.session.post(self.search_url, headers=self.headers)
            # print(f'内置的关联类型：{resp.json()}')
            types = jsonpath库.jsonpath(resp.json(), '$..bk_asst_id')[::-1]
            types.remove('bk_mainline')
            ObjectAsst.asst_types = types
            print(f'内置的关联类型获取成功！, {ObjectAsst.asst_types}')
        except:
            raise

    def create_asst(self, bk_obj_id: str, bk_asst_obj_id: str, bk_asst_id: str, mapping: str = "n:n"):
        # {
        #     "bk_obj_asst_id": "hjtautomodule_1716272952_belong_hjtautomodule_1716272957",
        #     "bk_obj_asst_name": "",
        #     "bk_obj_id": "hjtautomodule_1716272952",
        #     "bk_asst_obj_id": "hjtautomodule_1716272957",
        #     "bk_asst_id": "belong",
        #     "mapping": "n:n"
        # }
        data = {
            "bk_asst_id": bk_asst_id,
            "bk_obj_id": bk_obj_id,
            "bk_asst_obj_id": bk_asst_obj_id,
            "bk_obj_asst_id": '_'.join([bk_obj_id, bk_asst_id, bk_asst_obj_id]),
            "mapping": mapping,
            "bk_obj_asst_name": ""
        }
        try:
            resp = self.session.post(self.create_url, json=data, headers=self.headers)
            # print(f'内置的关联类型：{resp.json()}')
            print(f'{bk_obj_id}成功【{bk_asst_id}关联】{bk_asst_obj_id}！')
        except:
            raise


if __name__ == '__main__':
    pass
